package ChanSyncObj

import (
	"sync"
	"time"
)

/**
说明：多线程之间，基于go的chan实现的简单消息等待/通知机制
*/

var (
	syncMap sync.Map
)

type entity struct {
	waiting bool
	ch      chan interface{}
}

func Instance(key string) {
	_, ok := syncMap.Load(key)
	if ok {
		return
	}

	data := &entity{}
	data.ch = make(chan interface{}, 1)

	syncMap.Store(key, data)
}

func Release(key string) {
	val, ok := syncMap.Load(key)
	if !ok {
		return
	}
	data := val.(*entity)

	close(data.ch)
	syncMap.Delete(key)
}

func SimpleWait(uuid string, timeout int64) interface{} {
	Instance(uuid)
	message := Wait(uuid, timeout)
	Release(uuid)

	return message
}

func Wait(key string, timeout int64) interface{} {
	val, ok := syncMap.Load(key)
	if !ok {
		return nil
	}
	data := val.(*entity)
	data.waiting = true

	select {
	case message := <-data.ch:
		data.waiting = false
		return message
	case <-time.After(time.Duration(timeout) * time.Millisecond):
		data.waiting = false
		return nil
	}
}

func Notify(key string, message interface{}) {
	val, ok := syncMap.Load(key)
	if !ok {
		return
	}
	data := val.(*entity)

	// 检查：是否已经满了
	if len(data.ch) == cap(data.ch) {
		return
	}

	data.ch <- message
}

func IsWaiting(key string) bool {
	val, ok := syncMap.Load(key)
	if !ok {
		return false
	}
	data := val.(*entity)

	return data.waiting
}
